package com.myblog.demo.service;

import com.myblog.demo.common.ApplicationVariable;
import com.myblog.demo.common.ArticleInfoVOConverterUtils;
import com.myblog.demo.entity.ArticleInfo;
import com.myblog.demo.entity.vo.ArticleInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Map;

/**
 * Redis 服务层：对 Redis 的相关操作
 */
@Service
public class RedisServer {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ArticleService articleService;

    /**
     * 根据文章 id 获取文章。
     * 首先尝试从 Redis 缓存中获取，如果缓存不存在，则从数据库中获取，并将其保存到 Redis 中
     *
     * @param aid 文章id
     * @return ArticleInfoVO
     */
    public ArticleInfoVO getDetailById(Integer aid) {
        // hash 类型操作对象
        HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();

        // key
        String cacheKey = ApplicationVariable.ARTICLE_KEY + aid;

        // 首先尝试从 Redis 中获取指定文章
        Map<Object, Object> entries = opsForHash.entries(cacheKey);
        if (!entries.isEmpty()) {
            // 成功从 Redis 中获取到对应文章，直接返回
            return ArticleInfoVOConverterUtils.convertToArticleInfoVO(entries);
        }

        // 没有缓存或者缓存为命中
        // 首先从 Redis 中获取对应文章
        ArticleInfoVO articleInfoVO = articleService.getDetailById(aid);

        // 将其保存到 Redis 缓存中
        if (articleInfoVO != null) {
            opsForHash.putAll(cacheKey, ArticleInfoVOConverterUtils.convertToMap(articleInfoVO));
            // 设置过期时间
            stringRedisTemplate.expire(cacheKey, Duration.ofHours(1));
        }

        // 返回
        return articleInfoVO;
    }

    /**
     * 修改文章，如果 Redis 中存在该文章的缓存，则同步更新该缓存
     *
     * @param articleInfo 修改的文章信息
     * @return 操作 MySQL 数据库的返回值
     */
    public int updateArticle(ArticleInfo articleInfo) {
        // 修改数据库中对应的文章信息
        int result = articleService.update(articleInfo);

        // 如果 Redis 缓存中存在改文章，则更新为修改后的文章
        HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
        String cacheKey = ApplicationVariable.ARTICLE_KEY + articleInfo.getId();
        if (!opsForHash.entries(cacheKey).isEmpty()) {
            // 更新 Redis 中的缓存
            ArticleInfoVO articleInfoVO = articleService.getDetailById(articleInfo.getId());
            opsForHash.putAll(cacheKey, ArticleInfoVOConverterUtils.convertToMap(articleInfoVO));
        }
        // 返回操作 MySQL 数据库结果
        return result;
    }

    /**
     * 通过文章 id 和 用户 id 删除指定文章，如果该文章存在 Redis 缓存中，则删除该缓存
     *
     * @param aid 文章 id
     * @param uid 用户 id
     * @return 操作 MySQL 数据库的返回值
     */
    public int deleteArticleByAIdAndUID(Integer aid, Integer uid) {
        int result = articleService.delByIdAndUid(aid, uid);
        // 如果 Redis 中存在该文章的缓存，则删除
        HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
        String cacheKey = ApplicationVariable.ARTICLE_KEY + aid;
        if (!opsForHash.entries(cacheKey).isEmpty()) {
            stringRedisTemplate.delete(cacheKey);
        }

        // 返回操作 MySQL 数据库的结果
        return result;
    }
}
